#include <2025Linux.h>
typedef struct node_s {
    int num;
    struct node_s * pNext;
} node_t;
typedef struct queue_s {
    node_t * pFront;
    node_t * pRear;
    int size;
} queue_t;//链式队列
typedef struct shareResource_s {
    queue_t queue;//queue里面的长度信息，起到flag的作用
    pthread_mutex_t mutex;
    pthread_cond_t cond1;//生产者等待
    pthread_cond_t cond2;//消费者等待
} shareResource_t;
int initQueue(queue_t * pqueue){
    memset(pqueue,0,sizeof(queue_t));
    return 0; // 返回int的意义是可能会有报错
}
int enQueue(queue_t *pqueue, int num){//入队 尾插法
    node_t * pNew = (node_t *)calloc(1,sizeof(node_t));
    pNew->num = num;
    if(pqueue->size == 0){
        pqueue->pFront = pNew;
        pqueue->pRear = pNew;
    }
    else{
        pqueue->pRear->pNext = pNew;
        pqueue->pRear = pNew;
    }
    ++pqueue->size;
    return 0;
}
int deQueue(queue_t * pqueue){//出队 头部删除法
    // 用户不会在链表为空的时候做删除
    node_t * pCur = pqueue->pFront;
    pqueue->pFront = pCur->pNext;
    free(pCur);
    // 如果删除完以后没有节点了，pRear的指向也要变
    if(pqueue->pFront == NULL){
        pqueue->pRear = NULL;
    }
    --pqueue->size;
    return 0;
}
int printQueue(queue_t *pqueue){
    node_t * pCur = pqueue->pFront;
    while(pCur != NULL){
        printf("%4d", pCur->num);
        pCur = pCur->pNext;
    }
    printf("\n");
    return 0;
}
//// 设计一个临时的main函数，它不完成业务，只是了为了测试已经完成部分功能
//// 单元测试
//int main(){
//    queue_t queue;
//    initQueue(&queue);
//    printf("after init: ");
//    printQueue(&queue);
//    for(int i = 0; i < 10; ++i){
//        int num = rand()%1000;
//        enQueue(&queue,num);
//        printf("after enQueue, num = %d, size = %d, ", num, queue.size);
//        printQueue(&queue);
//    }
//    printf("------------------------------\n");
//    for(int i = 0; i < 9; ++i){
//        deQueue(&queue);
//        printf("after deQueue, size = %d, ",queue.size);
//        printQueue(&queue);
//    }
//}
void *producer(void *arg){
    shareResource_t * pshareRes = (shareResource_t *)arg;
    while(1){
        pthread_mutex_lock(&pshareRes->mutex);
        if(pshareRes->queue.size >= 10){//当商品的个数太多的时候，需要等在cond1这里
            pthread_cond_wait(&pshareRes->cond1,&pshareRes->mutex);
        }
        int num = rand() % 1000; //num 是新生产的商品
        printf("before produce, size = %d, num = %d,",pshareRes->queue.size, num);
        printQueue(&pshareRes->queue);
        enQueue(&pshareRes->queue,num);
        printf("after produce, size = %d, num  =%d,", pshareRes->queue.size, num);
        printQueue(&pshareRes->queue);
        //生产者生产完成以后，要唤醒消费者
        pthread_cond_signal(&pshareRes->cond2);
        pthread_mutex_unlock(&pshareRes->mutex);

        sleep(3);
    }
}
void *consumer(void *arg){
    shareResource_t * pshareRes = (shareResource_t *)arg;
    sleep(5);
    while(1){
        pthread_mutex_lock(&pshareRes->mutex);
        if(pshareRes->queue.size <= 0){//当商品个数太少的要等，需要等在cond2这里
            pthread_cond_wait(&pshareRes->cond2,&pshareRes->mutex);
        }
        printf("before consume , size = %d, front = %d,",pshareRes->queue.size, pshareRes->queue.pFront->num);
        printQueue(&pshareRes->queue);
        deQueue(&pshareRes->queue);
        printf("after consume, size = %d,", pshareRes->queue.size);
        printQueue(&pshareRes->queue);
        //消费者消费完成以后，唤醒生产者
        pthread_cond_signal(&pshareRes->cond1);
        pthread_mutex_unlock(&pshareRes->mutex);
        sleep(1);
    }

}
int main(){
    // 准备好共享资源&初始化
    shareResource_t shareRes;
    initQueue(&shareRes.queue);
    pthread_mutex_init(&shareRes.mutex,NULL);
    pthread_cond_init(&shareRes.cond1,NULL);
    pthread_cond_init(&shareRes.cond2,NULL);
    // 准备好一开始的商品
    int num;
    for(int i = 0; i < 8; ++i){
        num = rand() % 1000;
        enQueue(&shareRes.queue,num);
        printf("after enQueue, num = %d, size = %d, ", num, shareRes.queue.size);
        printQueue(&shareRes.queue);
    }
    printf("-----------------------\n");
    pthread_t tid1,tid2,tid3,tid4,tid5; 
    pthread_create(&tid1,NULL,producer,&shareRes);
    pthread_create(&tid2,NULL,producer,&shareRes);
    pthread_create(&tid3,NULL,producer,&shareRes);
    pthread_create(&tid4,NULL,consumer,&shareRes);
    pthread_create(&tid5,NULL,consumer,&shareRes);

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    pthread_join(tid4,NULL);
    pthread_join(tid5,NULL);
}
